﻿using System.Collections.Generic;

namespace Jinndev
{

    /// <summary>
    /// 可观察的对象
    /// </summary>
    /// <typeparam name="T"></typeparam>
    [System.Serializable]
    public class ObservableObject<T>
    {

        public interface IChangeListener
        {
            void OnChange(ObservableObject<T> obsObj, T oldValue, T newValue);
        }

        protected T obj;
        protected List<IChangeListener> listenerList = new List<IChangeListener>();

        #region constructors
        public ObservableObject()
        {

        }

        public ObservableObject(T value)
        {
            this.obj = value;
        }

        public ObservableObject(T value, IChangeListener listener)
        {
            this.obj = value;
            AddChangeListener(listener);
        }

        public ObservableObject(IChangeListener listener)
        {
            AddChangeListener(listener);
        }

        public ObservableObject(params IChangeListener[] listeners)
        {
            if (listeners != null)
            {
                foreach (IChangeListener listener in listeners)
                {
                    AddChangeListener(listener);
                }
            }
        }
        #endregion constructors

        public T Value
        {
            get
            {
                return obj;
            }
            set
            {
                if (ReferenceEquals(obj, value) == false)
                {
                    T oldValue = obj;
                    T newValue = value;
                    obj = value;
                    FireOnChange(oldValue, newValue);
                }
            }
        }

        public bool IsEmpty()
        {
            return obj == null;
        }

        public void AddChangeListener(IChangeListener listener)
        {
            if (listener != null && listenerList.Contains(listener) == false)
            {
                listenerList.Add(listener);
            }
            else
            {
                UnityEngine.Debug.LogError("Invalid listener : " + listener);
            }
        }

        public void RemoveChangeListener(IChangeListener listener)
        {
            if (listener != null)
            {
                listenerList.Remove(listener);
            }
        }

        public void RemoveAllChangeListener()
        {
            listenerList.Clear();
        }

        /// <summary>
        /// Fire on change event manually
        /// </summary>
        public void FireOnChange()
        {
            FireOnChange(obj, obj);
        }

        public void FireOnChange(IChangeListener listener)
        {
            if (listener != null)
            {
                listener.OnChange(this, obj, obj);
            }
        }

        protected void FireOnChange(T oldValue, T newValue)
        {
            foreach (IChangeListener listener in listenerList)
            {
                if (listener != null)
                {
                    listener.OnChange(this, oldValue, newValue);
                }
            }
        }

    }

}